package virtualstock.request;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import javax.ejb.EJB;
import javax.ejb.EJBException;
import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import virtualstock.entity.Game;
import virtualstock.entity.Player;
import virtualstock.entity.Portfolio;
import virtualstock.exception.GameNotFoundException;
import virtualstock.exception.InvalidParameterException;
import virtualstock.exception.PlayerNotFoundException;
import virtualstock.exception.PortfolioNotFoundException;
import virtualstock.util.GameDetails;
import virtualstock.util.PortfolioDetails;

/**
 * Session Bean implementation class GameControllerBean
 */
@Stateful
public class GameControllerBean implements GameController {
        @PersistenceContext
    private EntityManager em;
    private String gameID;
   
    @EJB
        private PortfolioController portfolioController;

    /**
     * Default constructor.
     */
    public GameControllerBean() {
        // TODO Auto-generated constructor stub
    }

        @Override
        public void addPlayerToGame(Long playerID, Long gameID)
                throws InvalidParameterException, PlayerNotFoundException, GameNotFoundException, PortfolioNotFoundException {
                // adds a player to the game
                Player player = null;
                Game game = null;
               
                if (playerID == null) {
                        throw new InvalidParameterException("null playerID");
                }
                else if (gameID == null) {
                        throw new InvalidParameterException("null gameID");
                }
               
                try {
                        game = em.find(Game.class, gameID);
                       
                        if (gameID == null) {
                                throw new GameNotFoundException();
                        }
                } catch (Exception ex) {
                        throw new EJBException(ex);
                }
               
                try {
                        player = em.find(Player.class, playerID);
                       
                        if (player == null) {
                                throw new PlayerNotFoundException();
                        }
                        else {
                                game.addPlayer(player);
                        }
                } catch (Exception ex) {
                        throw new EJBException(ex);
                }
               
                // update the initial balance in portfolio
                BigDecimal initialBalance = game.getInitialBalance();
                System.out.println("game initialBalance is " + initialBalance);
                PortfolioDetails portfolioDetails = portfolioController.getPortfolioDetailsByGameAndPlayer(gameID, playerID);
                Portfolio portfolio = null;
                try {
                        portfolio = em.find(Portfolio.class, portfolioDetails.getPortfolioID());
                       
                        if (portfolio == null) {
                                throw new PortfolioNotFoundException();
                        } else {
                                System.out.println("found portfolio: " + portfolio.getPortfolioID());
                                portfolio.setBalance(initialBalance);
                                em.flush();     // write to database
                                em.refresh(portfolio);
                        }
                } catch (Exception ex) {
                        throw new EJBException(ex);
                }
               
        }

        @Override
        public void addStockToGame(Long stockID, Long gameID) {
                // TODO Auto-generated method stub
               
        }

        @Override
        public Long createNewGame(GameDetails details)
                throws PlayerNotFoundException, InvalidParameterException {
                // makes a new game and enters it into db
                Game game = null;
                Player player = null;
               
                // may be add more checks for the inputs
               
                try {
                        player = em.find(Player.class, details.getCreator());
                       
                        if (player == null) {
                                throw new PlayerNotFoundException();
                        }
                } catch (Exception ex) {
                        throw new EJBException(ex);
                }
               
                try {
                        game = new Game(
                                        details.getGameName(),
                                        details.getCreator(),
                                        details.getMaxPlayer(),
                                        details.getInitialBalance(),
                                        details.getStartDate());
                        em.persist(game);
                        //game.addPlayer(player);
                } catch (Exception ex) {
                        throw new EJBException(ex);
                }
               
                //return game.getGameID();
                return findCreatedGameID(details);
        }

        @Override
        public GameDetails getGameDetails(Long gameID)
                throws InvalidParameterException, GameNotFoundException {
               
                // !!! don't use this until portfolio is created
                // because getPlayerIDs is not done.
               
                GameDetails details = null;
                Game game = null;
               
                if (gameID == null) {
                        throw new InvalidParameterException("null gameID");
                }
               
                try {
                        game = em.find(Game.class, gameID);
                       
                        if (game == null) {
                                System.err.println("GameControllerBean.getGameDetails: Game not found.");
                                throw new GameNotFoundException(gameID);
                        }
                        else {
                                details = new GameDetails(
                                                gameID,
                                                game.getGameName(),
                                                game.getCreator(),
                                                game.getMaxPlayer(),
                                                game.getInitialBalance(),
                                                game.getStartDate());
                                // currently, not using the following two lines
                                List<Long> playerIDs = this.getPlayerIDs(gameID);
                                details.setPlayerIDs(playerIDs);
                        }
                } catch (Exception ex) {
                        System.err.println("GameControllerBean.getGameDetails: Caught an exception.");
                        ex.getStackTrace();
                }
               
                return details;
        }

        @Override
        public List<GameDetails> getGamesOfPlayer(Long playerID)
                throws InvalidParameterException, PlayerNotFoundException {
                // returns a List of GameDetails
               
                Collection<Game> games = null;
                Player player = null;
               
                if (playerID == null) {
                        throw new InvalidParameterException("null playerID");
                }
               
                try {
                        player = em.find(Player.class, playerID);
                        em.refresh(player);
                       
                        if (player == null) {
                                throw new PlayerNotFoundException();
                        }
                        else {
                                games = player.getGames();
                        }
                } catch (Exception ex) {
                        throw new EJBException(ex);
                }
               
                return copyGamesToDetails(games);
        }


        @Override
        public List<Long> getStockIDs(Long gameID) {
                // TODO !!! wait until stock is created
                return null;
        }

        @Override
        public void removeGame(Long gameID)
                throws InvalidParameterException, GameNotFoundException {
                // removes game
                Game game = null;
               
                if (gameID == null) {
                        throw new InvalidParameterException("null gameID");
                }
               
                try {
                        game = em.find(Game.class, gameID);
                       
                        if (game == null) {
                                throw new GameNotFoundException();
                        }
                        else {
                                em.remove(game);
                        }
                } catch (Exception ex) {
                        throw new EJBException(ex);
                }
        }

        @Override
        public void removePlayerFromGame(Long playerID, Long gameID)
                throws InvalidParameterException, PlayerNotFoundException, GameNotFoundException {
                // removes a player from this game, but the player is not removed from the db
               
                Game game = null;
                Player player = null;
               
                if (playerID == null) {
                        throw new InvalidParameterException("null playerID");
                }
                else if (gameID == null) {
                        throw new InvalidParameterException("null gameID");
                }
               
                try {
                        game = em.find(Game.class, gameID);
                       
                        if (game == null) {
                                throw new GameNotFoundException();
                        }
                } catch (Exception ex) {
                        throw new EJBException(ex);
                }
               
                try {
                        player = em.find(Player.class, playerID);
                       
                        if (player == null) {
                                throw new PlayerNotFoundException();
                        }
                        else {
                                game.removePlayer(player);
                        }
                } catch (Exception ex) {
                        throw new EJBException(ex);
                }
        }

        @Override
        public void removeStockFromGame(Long stockID, Long gameID) {
                // TODO !!! wait until stock is created
               
        }

        @Override
        public List<Long> getPlayerIDs(Long gameID)
                throws InvalidParameterException, GameNotFoundException {
                // !!! don't use this until portfolio is created
                List<Player> players = null;
               
                if (gameID == null) {
                        throw new InvalidParameterException("null gameID");
                }
               
                try {
                        // this can use portfolio
                        players = em.createNamedQuery("Player.FindAllPlayersOfGame").setParameter("gameID", gameID).getResultList();
                       
                        if (players == null) {
                                throw new GameNotFoundException();
                        }
                } catch (Exception ex) {
                        throw new EJBException(ex);
                }
               
                return copyGameIDsToList(players);
        }
       
        @Override
        public List<GameDetails> getAllAvailableGames(){
                Collection games = null;
                try{
                        games = (List<GameDetails>)em.createNamedQuery("Game.FindAllAvailableGame").getResultList();
                }catch (Exception ex) {
                        throw new EJBException(ex.getMessage());
                }
               
                if(games.isEmpty())
                        return null;
                else
                        return copyGamesToDetails(games);
        }
       
        private List<Long> copyGameIDsToList(List<Player> players) {
                List<Long> playerIDList = new ArrayList<Long>();
                Iterator<Player> i = players.iterator();
               
                while (i.hasNext()) {
                        Player player = i.next();
                        playerIDList.add(player.getPlayerID());
                }
               
                return playerIDList;
        }
       
        private List<GameDetails> copyGamesToDetails(Collection<Game> games) {
                List<GameDetails> detailsList = new ArrayList<GameDetails>();
                Iterator<Game> i = games.iterator();
               
                while (i.hasNext()) {
                        Game game = i.next();
                        GameDetails details = new GameDetails(
                                        game.getGameID(),
                                        game.getGameName(),
                                        game.getCreator(),
                                        game.getMaxPlayer(),
                                        game.getInitialBalance(),
                                        game.getStartDate());
                        detailsList.add(details);
                }
               
                return detailsList;
        }
       
        private Long findCreatedGameID(GameDetails details) {
                Long gameID = null;
               
                Object gameIDObject = em.createNamedQuery("Game.FindCreatedGameID")
                        .setParameter("gameName", details.getGameName())
                        .setParameter("creator", details.getCreator())
                        .setParameter("maxPlayer", details.getMaxPlayer())
                        .setParameter("initialBalance", details.getInitialBalance())
                        .setParameter("startDate", details.getStartDate())
                        .getSingleResult();
               
                if (gameIDObject != null) {
                        gameID = new Long(gameIDObject.toString());
                }
               
                return gameID;
        }



}
